package org.shj.jvm.oom;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

/**
 * -verbose:gc -Xms10M -Xmx10M -XX:MaxDirectMemorySize=5M -XX:+PrintGCDetails
 * @author Shen Huang Jian
 * 
 * ByteBuffer.allocate(capability) 是分配 JVM 堆内存，属于 GC 管辖范围，需要内存拷贝所以速度相对较慢；
 * ByteBuffer.allocateDirect(capability)是分配 OS 本地内存，不属于 GC 管辖范围，由于不需要内存拷贝所以速度相对较快；
 *
 *  解决方案
 *
 * Java 只能通过 ByteBuffer.allocateDirect 方法使用 Direct ByteBuffer，因此，可以通过 Arthas 等在线诊断工具拦截该方法进行排查
 * 检查是否直接或间接使用了 NIO，如 netty，jetty 等
 * 通过启动参数 -XX:MaxDirectMemorySize 调整 Direct ByteBuffer 的上限值
 * 检查 JVM 参数是否有 -XX:+DisableExplicitGC 选项，如果有就去掉，因为该参数会使 System.gc() 失效
 * 检查堆外内存使用代码，确认是否存在内存泄漏；或者通过反射调用 sun.misc.Cleaner 的 clean() 方法来主动释放被 Direct ByteBuffer 持有的内存空间
 * 内存容量确实不足，升级配置
 *
 */
public class DirectOutofMemory {
	
	private static int _MB = 2*1024*1024;
	private static int cnt = 0;

	public static void main(String[] args) {
		System.out.println("maxDirectMemory is:"+sun.misc.VM.maxDirectMemory() / 1024 / 1024 + "MB");
		List<ByteBuffer> list = new ArrayList<>();
		try{
			int i = 0;
			while(i < 100){
				ByteBuffer bb = ByteBuffer.allocateDirect(_MB);
				list.add(bb);
				cnt++;
				i++;
			}
		}catch(Exception e){
			e.printStackTrace();
			System.out.println("cnt: " + cnt);
			System.exit(1);
		}catch(Error e){
			e.printStackTrace();
			System.out.println("In Erro " );
			System.out.println("cnt: " + cnt);
			System.exit(1);
		}

	}

}
